#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
简化版流状态监控服务
直接从MySQL读取流信息，检测可访问性，更新状态
"""

import asyncio
import logging
from datetime import datetime
from typing import Dict, List, Any

from app.core.config import settings


class StreamMonitor:
    """简化版流状态监控服务"""
    
    def __init__(self, ffmpeg_service=None):
        self.ffmpeg_service = ffmpeg_service or get_ffmpeg_service()
        self.logger = logging.getLogger(__name__)
        self.monitoring_tasks = {}
        self.is_monitoring = False
        
        # 从配置读取参数
        self.max_concurrent_checks = settings.STREAM_MONITOR_MAX
        self.semaphore = asyncio.Semaphore(self.max_concurrent_checks)
        self.monitor_interval = settings.STREAM_MONITOR_TIME
    
    async def check_stream_status(self, stream_url: str, stream_type: str = "rtmp") -> Dict[str, Any]:
        """检查单个流的状态"""
        try:
            self.logger.debug(f"开始检查流状态 - URL: {stream_url}, 类型: {stream_type}")
            
            if not self.ffmpeg_service:
                self.logger.error("FFmpeg服务未初始化")
                return {
                    "status": "inactive",
                    "error": "FFmpeg服务未初始化"
                }
            
            # self.logger.debug(f"使用FFmpeg服务验证流: {stream_url}")
            
            # 使用FFmpeg检查流，添加15秒超时（比内部10秒稍长）
            try:
                result = await asyncio.wait_for(
                    self.ffmpeg_service.validate_stream(stream_url),
                    timeout=15
                )
                # self.logger.debug(f"FFmpeg验证结果: {result}")
            except asyncio.TimeoutError:
                self.logger.warning(f"流检测超时(15秒) - URL: {stream_url}")
                return {
                    "status": "inactive",
                    "error": "流检测超时(15秒)"
                }
            except Exception as e:
                self.logger.error(f"FFmpeg验证异常 - URL: {stream_url}, 错误: {str(e)}")
                return {
                    "status": "inactive",
                    "error": f"FFmpeg验证失败: {str(e)}"
                }
            
            if result["valid"]:
                self.logger.debug(f"流验证成功 - URL: {stream_url}")
                # 获取详细信息
                info = result.get("info", {})
                streams = info.get("streams", [])
                
                self.logger.debug(f"流信息详情: 总流数={len(streams)}, 格式信息={info.get('format', {})}")
                
                # 提取视频流信息
                video_stream = next((s for s in streams if s.get("codec_type") == "video"), {})
                audio_stream = next((s for s in streams if s.get("codec_type") == "audio"), {})
                
                self.logger.debug(f"视频流信息: {video_stream}")
                self.logger.debug(f"音频流信息: {audio_stream}")
                
                # 提取分辨率信息
                width = video_stream.get("width", 0)
                height = video_stream.get("height", 0)
                resolution = f"{width}x{height}" if width and height else ""
                
                status_result = {
                    "status": "active",
                    "video_codec": video_stream.get("codec_name", ""),
                    "audio_codec": audio_stream.get("codec_name", ""),
                    "resolution": resolution,
                    "bitrate": int(info.get("format", {}).get("bit_rate", 0))
                }
                
                # self.logger.info(f"流状态检查完成 - URL: {stream_url}, 状态: active, 分辨率: {resolution}")
                return status_result
            else:
                # 流不可访问
                error_msg = result.get("error", "Stream not accessible")
                self.logger.info(f"流不可访问 - URL: {stream_url}, 错误: {error_msg}")
                return {
                    "status": "inactive",
                    "error": error_msg
                }
                
        except Exception as e:
            self.logger.error(f"检查流状态异常 - URL: {stream_url}, 错误类型: {type(e).__name__}, 错误: {str(e)}")
            import traceback
            self.logger.error(f"详细堆栈: {traceback.format_exc()}")
            return {
                "status": "inactive",
                "error": str(e)
            }
    
    async def get_streams_from_db(self) -> List[Dict[str, Any]]:
        """从MySQL获取所有流列表"""
        try:
            from sqlalchemy import select
            from app.core.database import SessionLocal
            from app.models.stream import Stream
            
            session = SessionLocal()
            try:
                stmt = select(Stream)  # 查询所有流，不限制inuse
                result = session.execute(stmt)
                streams = result.scalars().all()
                
                return [
                    {
                        "id": stream.id,
                        "url": stream.url,
                        "name": stream.name,
                        "stream_type": stream.stream_type,
                        "inuse": stream.inuse  # 添加inuse字段
                    }
                    for stream in streams
                ]
            finally:
                session.close()
                
        except Exception as e:
            self.logger.error(f"获取流列表失败: {str(e)}")
            return []

    async def _refresh_streams_from_db(self):
        """从数据库全量刷新流列表 - 优化为单次遍历"""
        try:
            # 获取数据库中所有流
            all_streams = await self.get_streams_from_db()
            
            # 获取当前正在监控的流
            current_monitoring_ids = set(self.monitoring_tasks.keys())
            
            # 单次遍历处理所有流
            for stream in all_streams:
                stream_id_str = str(stream['id'])
                
                if stream['inuse'] > 0:
                    # 需要监控的流
                    if stream_id_str not in current_monitoring_ids:
                        task = asyncio.create_task(
                            self.monitor_single_stream(
                                stream['id'], 
                                stream['url'], 
                                stream.get('stream_type', 'rtmp')
                            )
                        )
                        self.monitoring_tasks[stream_id_str] = task
                        self.logger.info(f"启动新流监控: {stream_id_str} - {stream['url']} (inuse={stream['inuse']})")
                else:
                    # 需要停止监控的流
                    if stream_id_str in current_monitoring_ids:
                        await self._stop_stream_monitoring(stream_id_str)
                        self.logger.info(f"停止流监控: {stream_id_str} - {stream['url']} (inuse={stream['inuse']})")
                        
        except Exception as e:
            self.logger.error(f"数据库刷新失败: {e}")

    async def monitor_single_stream(self, stream_id: int, stream_url: str, stream_type: str = "rtmp"):
        """监控单个流 - 移除interval参数，统一使用配置"""
        while True:
            try:
                # 检测流状态
                status_info = await self.check_stream_status(stream_url, stream_type)
                
                # 记录检测日志
                self.logger.info(f"检测流 ID: {stream_id}, URL: {stream_url}, 类型: {stream_type}, 状态: {status_info['status']}")
                
                # 更新到数据库
                await self.update_stream_in_db(stream_id, status_info)
                
                # 使用配置间隔
                await asyncio.sleep(settings.STREAM_MONITOR_TIME)
                
            except asyncio.CancelledError:
                self.logger.info(f"停止监控流 - ID: {stream_id}, URL: {stream_url}")
                break
            except Exception as e:
                self.logger.error(f"监控流异常 - ID: {stream_id}, URL: {stream_url}, 错误: {str(e)}")
                await asyncio.sleep(settings.STREAM_MONITOR_TIME)

    async def _stop_stream_monitoring(self, stream_id: str):
        """停止单个流的监控"""
        if stream_id in self.monitoring_tasks:
            task = self.monitoring_tasks[stream_id]
            if not task.done():
                task.cancel()
                try:
                    await task
                except asyncio.CancelledError:
                    pass
            del self.monitoring_tasks[stream_id]

    # 移除无实际作用的add_stream和remove_stream方法
    # 现在由定时刷新统一处理流的添加和移除
    
    async def start_monitoring(self, interval=None):
        """启动监控服务 - 使用后台任务非阻塞方式"""
        if self.is_monitoring:
            self.logger.warning("监控服务已经在运行中")
            return
            
        self.is_monitoring = True
        self.monitor_interval = interval or settings.STREAM_MONITOR_TIME
        
        self.logger.info(f"启动流监控服务，间隔: {self.monitor_interval}秒")
        
        # 立即执行一次刷新
        await self._refresh_streams_from_db()
        
        # 启动后台定时任务
        self._monitor_task = asyncio.create_task(self._periodic_refresh_streams())
        
    async def _periodic_refresh_streams(self):
        """后台定时刷新流列表 - 非阻塞"""
        while self.is_monitoring:
            try:
                await asyncio.sleep(self.monitor_interval)
                if self.is_monitoring:  # 再次检查，可能在sleep期间被停止
                    await self._refresh_streams_from_db()
            except asyncio.CancelledError:
                break
            except Exception as e:
                self.logger.error(f"定时刷新流列表时发生错误: {e}")
                await asyncio.sleep(5)  # 出错后等待5秒再重试
                
    async def stop_monitoring(self):
        """停止监控服务"""
        if not self.is_monitoring:
            return
            
        self.is_monitoring = False
        self.logger.info("正在停止流监控服务...")
        
        # 取消后台任务
        if hasattr(self, '_monitor_task') and self._monitor_task and not self._monitor_task.done():
            self._monitor_task.cancel()
            try:
                await self._monitor_task
            except asyncio.CancelledError:
                pass
                
        # 停止所有流监控
        for stream_id in list(self.monitoring_tasks.keys()):
            await self._stop_stream_monitoring(stream_id)
            
        self.logger.info("流监控服务已停止")
    
    async def update_stream_in_db(self, stream_id: int, status_info: Dict[str, Any]):
        """更新MySQL中的流信息"""
        try:
            from sqlalchemy import update
            from app.core.database import SessionLocal
            from app.models.stream import Stream
            
            session = SessionLocal()
            try:
                # 基础更新字段：状态和检查时间
                update_values = {
                    "status": status_info["status"],
                    "last_check": datetime.now()                   
                }
                
                # 只有流状态为active时，才更新编解码器信息
                if status_info["status"] == "active":
                    # 添加编解码器信息和分辨率
                    if "video_codec" in status_info:
                        update_values["video_codec"] = status_info["video_codec"]
                    if "audio_codec" in status_info:
                        update_values["audio_codec"] = status_info["audio_codec"]
                    if "bitrate" in status_info and status_info["bitrate"]:
                        update_values["bitrate"] = status_info["bitrate"]
                    if "resolution" in status_info and status_info["resolution"]:
                        update_values["resolution"] = status_info["resolution"]
                    
                    self.logger.debug(f"流正常，更新完整信息 - ID: {stream_id}, 状态: {status_info['status']}, 分辨率: {status_info.get('resolution', 'N/A')}, 视频编码: {status_info.get('video_codec', 'N/A')}, 音频编码: {status_info.get('audio_codec', 'N/A')}")
                else:
                    # 流异常时，只更新状态，保持原有的编解码器信息不变
                    self.logger.warning(f"流异常，仅更新状态 - ID: {stream_id}, 状态: {status_info['status']}, 错误: {status_info.get('error', '未知错误')}")
                
                stmt = (
                    update(Stream)
                    .where(Stream.id == stream_id)
                    .values(**update_values)
                )
                session.execute(stmt)
                session.commit()
                
            finally:
                session.close()
                
        except Exception as e:
            self.logger.error(f"更新流信息失败: {str(e)}")
            if 'update_values' in locals():
                self.logger.error(f"尝试更新的字段: {list(update_values.keys())}")
            raise


# StreamMonitor单例实例
_stream_monitor_instance = None

def get_stream_monitor():
    """获取StreamMonitor单例实例"""
    global _stream_monitor_instance
    if _stream_monitor_instance is None:
        from app.services.ffmpeg_service import get_ffmpeg_service
        ffmpeg_service = get_ffmpeg_service()
        _stream_monitor_instance = StreamMonitor(ffmpeg_service=ffmpeg_service)
    return _stream_monitor_instance